//Derek Connell (conned2) 2/10/10

#include <cstdio>
#include <cassert>
#include <vector>
#include <iostream>
#include <map>
// Included files for OpenGL Rendering
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif

#include "mesh.h"
#include "edge.h"
#include "vertex.h"
#include "triangle.h"
#include "glCanvas.h"
#include "cloth.h"

using namespace std;

int deleteRepeats(vector<Triangle*> tobedeleted,vector<Triangle*> atriangles,vector<Triangle*> btriangles, Vertex * apoint, Vertex * bpoint);
int Triangle::next_triangle_id = 0;


// =======================================================================
// MESH DESTRUCTOR 
// =======================================================================


Mesh::~Mesh() {
  // delete all the triangles
  std::vector<Triangle*> todo;
  for (triangleshashtype::iterator iter = triangles.begin();
       iter != triangles.end(); iter++) {
    Triangle *t = iter->second;
    todo.push_back(t);
  }
  int num_triangles = todo.size();
  for (int i = 0; i < num_triangles; i++) {
    removeTriangle(todo[i]);
  }
  // delete all the vertices
  int num_vertices = numVertices();
  for (int i = 0; i < num_vertices; i++) {
    delete vertices[i];
  }
}

// =======================================================================
// MODIFIERS:   ADD & REMOVE
// =======================================================================

Vertex* Mesh::addVertex(const Vec3f &position) {
  int index = numVertices();
  Vertex *v = new Vertex(index, position);
  vertices.push_back(v);
  if (numVertices() == 1)
    bbox = BoundingBox(position,position);
  else 
    bbox.Extend(position);
  return v;
}


void Mesh::addTriangle(Vertex *a, Vertex *b, Vertex *c) {
  // create the triangle
  Triangle *t = new Triangle();
  // create the edges
  Edge *ea = new Edge(a,b,t);
  Edge *eb = new Edge(b,c,t);
  Edge *ec = new Edge(c,a,t);
  // point the triangle to one of its edges
  t->setEdge(ea);
  // connect the edges to each other
  ea->setNext(eb);
  eb->setNext(ec);
  ec->setNext(ea);
  // verify these edges aren't already in the mesh 
  // (which would be a bug, or a non-manifold mesh)
  /*assert (edges.find(std::make_pair(a,b)) == edges.end());
  assert (edges.find(std::make_pair(b,c)) == edges.end());
  assert (edges.find(std::make_pair(c,a)) == edges.end());*/
  // add the edges to the master list
  edges[std::make_pair(a,b)] = ea;
  edges[std::make_pair(b,c)] = eb;
  edges[std::make_pair(c,a)] = ec;
  // connect up with opposite edges (if they exist)
  edgeshashtype::iterator ea_op = edges.find(std::make_pair(b,a)); 
  edgeshashtype::iterator eb_op = edges.find(std::make_pair(c,b)); 
  edgeshashtype::iterator ec_op = edges.find(std::make_pair(a,c)); 
  if (ea_op != edges.end()) { ea_op->second->setOpposite(ea); }
  if (eb_op != edges.end()) { eb_op->second->setOpposite(eb); }
  if (ec_op != edges.end()) { ec_op->second->setOpposite(ec); }
  // add the triangle to the master list
  assert (triangles.find(t->getID()) == triangles.end());
  triangles[t->getID()] = t;
}


void Mesh::removeTriangle(Triangle *t) {
  Edge *ea = t->getEdge();
  Edge *eb = ea->getNext();
  Edge *ec = eb->getNext();
  Vertex *a = ea->getStartVertex();
  Vertex *b = eb->getStartVertex();
  Vertex *c = ec->getStartVertex();
  // remove these elements from master lists
  edges.erase(std::make_pair(a,b)); 
  edges.erase(std::make_pair(b,c)); 
  edges.erase(std::make_pair(c,a)); 
  triangles.erase(t->getID());
  // clean up memory
  delete ea;
  delete eb;
  delete ec;
  delete t;
}


// =======================================================================
// Helper functions for accessing data in the hash table
// =======================================================================

Edge* Mesh::getMeshEdge(Vertex *a, Vertex *b) const {
  edgeshashtype::const_iterator iter = edges.find(std::make_pair(a,b));
  if (iter == edges.end()) return NULL;
  return iter->second;
}

Vertex* Mesh::getChildVertex(Vertex *p1, Vertex *p2) const {
  vphashtype::const_iterator iter = vertex_parents.find(std::make_pair(p1,p2)); 
  if (iter == vertex_parents.end()) return NULL;
  return iter->second; 
}

void Mesh::setParentsChild(Vertex *p1, Vertex *p2, Vertex *child) {
  assert (vertex_parents.find(std::make_pair(p1,p2)) == vertex_parents.end());
  vertex_parents[std::make_pair(p1,p2)] = child; 
}


// =======================================================================
// the load function parses very simple .obj files
// the basic format has been extended to allow the specification 
// of crease weights on the edges.
// =======================================================================

void Mesh::Load(const char *input_file) {
  
  std::cout << "Opening file " << input_file << std::endl;
  FILE *objfile = fopen(input_file,"r");
  if (objfile == NULL) {
    printf ("ERROR! CANNOT OPEN '%s'\n",input_file);
    return;
  }

  char line[200];
  char token[100];
  char atoken[100];
  char btoken[100];
  char ctoken[100];
  float x,y,z;
  int a,b,c,d,e;
  
  int index = 0;
  int vert_count = 0;
  int vert_index = 1;
  
  while (fgets(line, 200, objfile)) {   
    int token_count = sscanf (line, "%s\n",token);
    if (token_count == -1) continue;
    a = b = c = d = e = -1;
    if (!strcmp(token,"usemtl") ||
	!strcmp(token,"g")) {
      vert_index = 1; 
      index++;
    } else if (!strcmp(token,"v")) {
      vert_count++;
      sscanf (line, "%s %f %f %f\n",token,&x,&y,&z);
      addVertex(Vec3f(x,y,z));
    } else if (!strcmp(token,"f")) {
      int num = sscanf (line, "%s %s %s %s\n",token,
			atoken,btoken,ctoken);
      sscanf (atoken,"%d",&a);
      sscanf (btoken,"%d",&b);
      sscanf (ctoken,"%d",&c);
      assert (num == 4);
      a -= vert_index;
      b -= vert_index;
      c -= vert_index;
      assert (a >= 0 && a < numVertices());
      assert (b >= 0 && b < numVertices());
      assert (c >= 0 && c < numVertices());
      addTriangle(getVertex(a),getVertex(b),getVertex(c)); 
    } else if (!strcmp(token,"e")) {
      int num = sscanf (line, "%s %s %s %s\n",token,atoken,btoken,ctoken);
      assert (num == 4);
      sscanf (atoken,"%d",&a);
      sscanf (btoken,"%d",&b);
      if (!strcmp(ctoken,"inf")) x = 1000000; // this is close to infinity...
      else sscanf (ctoken,"%f",&x);
      Vertex *va = getVertex(a);
      Vertex *vb = getVertex(b);
      Edge *ab = getMeshEdge(va,vb);
      Edge *ba = getMeshEdge(vb,va);
      assert (ab != NULL);
      assert (ba != NULL);
      ab->setCrease(x);
      ba->setCrease(x);
    } else if (!strcmp(token,"vt")) {
    } else if (!strcmp(token,"vn")) {
    } else if (token[0] == '#') {
    } else {
      printf ("LINE: '%s'",line);
    }
  }
  
  Vec3f temp;
  for (int i = 0; i < numVertices(); ++i)
  {
      
      temp = getVertex(i)->getPos() - getVertex(0)->getPos();
      std::cout << "local pos = " << temp << std::endl;
      localAdjust.push_back(temp);
  }
  
  

 
}

void Mesh::EraseCutConnections(Vertex *va)
{
	//return;
	int i = va->relationshipParticle->theI;
	int j = va->relationshipParticle->theJ;
	//cout<<"1"<<endl;
	if(i<cloth->nx && j<cloth->ny && i>=0 && j>=0 )
	{
		//cout<<"2"<<endl;
		vector<pair<int, int> > vShear = cloth->getParticle(i,j).shear;
		for(unsigned int ii=0; ii<vShear.size(); ii++)
		{
			if(cloth->getParticle(vShear[ii].first,vShear[ii].second).completeCUT)
			{
				cloth->getParticle(i,j).shear.erase( cloth->getParticle(i,j).shear.begin() + ii);
				//ii-=1;
			}
			
		}
		/*cout<<"3"<<endl;
		if(i<cloth->nx && j<cloth->ny && i>=0 && j>=0 )
		{
			vector<pair<int, int> > vStruc = cloth->getParticle(i,j).struc;
			for(unsigned int ii=0; ii<vStruc.size(); ii++)
			{
				if(cloth->getParticle(vShear[ii].first,vShear[ii].second).completeCUT)
				{
					cloth->getParticle(i,j).struc.erase( cloth->getParticle(i,j).struc.begin() + ii);
					//ii-=1;
				}
			}
		}
		cout<<"4"<<endl;*/
	}
	
}

void Mesh::ShearIt(Vertex* va,Vertex* vb)
{
	int i = va->relationshipParticle->theI;
	int j = va->relationshipParticle->theJ;
	int i2 = vb->relationshipParticle->theI;
	int j2 = vb->relationshipParticle->theJ;
	//cout<<"start1"<<endl;
	if(i<cloth->nx && j<cloth->ny && i2<cloth->nx && j2<cloth->ny && i>=0 && j>=0 && i2>=0 && j2>=0)
	{
		vector<pair<int, int> > vShear = cloth->getParticle(i,j).shear;
		for(unsigned int ii=0; ii<vShear.size(); ii++)
		{
			if(vShear[ii].first == i2 && vShear[ii].second == j2)
			{
				vector<pair<int, int> > v2Shear = cloth->getParticle(i2,j2).shear; //vShear[ii].first,vShear[ii].second).shear;
				for(unsigned int jj=0; jj<v2Shear.size(); jj++)
				{
					if(v2Shear[jj].first == i && v2Shear[jj].second == j)
					{
						cloth->getParticle(i2,j2).shear.erase(cloth->getParticle(i2,j2).shear.begin()+jj);
						//cloth->getParticle(vShear[ii].first,vShear[ii].second).shear.erase(cloth->getParticle(vShear[ii].first,vShear[ii].second).shear.begin()+jj);
						break;						
					}
				}
				
				
				cloth->getParticle(i,j).shear.erase(cloth->getParticle(i,j).shear.begin()+ii);
				break;
			}
			
		}
	}
	//cout<<"start2"<<endl;
}

void Mesh::HandleShear(Vertex* va)
{ 
	int i = va->relationshipParticle->theI;
	int j = va->relationshipParticle->theJ;
	
	vector<pair<int, int> > vShear = cloth->getParticle(i,j).shear;
	for(unsigned int ii=0; ii<vShear.size(); ii++)
	{
		vector<pair<int, int> > v2Shear = cloth->getParticle(vShear[ii].first,vShear[ii].second).shear;
		for(unsigned int jj=0; jj<v2Shear.size(); jj++)
		{
			if(v2Shear[jj].first == i && v2Shear[jj].second == j)
			{
				cloth->getParticle(vShear[ii].first,vShear[ii].second).shear.erase(cloth->getParticle(vShear[ii].first,vShear[ii].second).shear.begin()+jj); 
			}
		}
	}
	//cloth->getParticle(i,j).shear.empty();
}


void Mesh::HandleStruc(Vertex* va)
{ 
	int i = va->relationshipParticle->theI;
	int j = va->relationshipParticle->theJ;
	
	vector<pair<int, int> > vStruc = cloth->getParticle(i,j).struc;
	for(unsigned int ii=0; ii<vStruc.size(); ii++)
	{
		vector<pair<int, int> > v2Struc = cloth->getParticle(vStruc[ii].first,vStruc[ii].second).struc;
		for(unsigned int jj=0; jj<v2Struc.size(); jj++)
		{
			if(v2Struc[jj].first == i && v2Struc[jj].second == j)
			{
				cloth->getParticle(vStruc[ii].first,vStruc[ii].second).struc.erase(cloth->getParticle(vStruc[ii].first,vStruc[ii].second).struc.begin()+jj); //v2Shear.erase(v2Shear.begin()+jj);
			}
		}
		//cloth->getParticle(i,j).struc.erase(cloth->getParticle(i,j).struc.begin()+ii); //vShear.erase(vShear.begin()+ii);
	}
	vector<pair<int, int> > vBend = cloth->getParticle(i,j).bend;
	for(unsigned int ii=0; ii<vBend.size(); ii++)
	{
		vector<pair<int, int> > v2Bend = cloth->getParticle(vBend[ii].first,vBend[ii].second).bend;
		for(unsigned int jj=0; jj<v2Bend.size(); jj++)
		{
			if(v2Bend[jj].first == i && v2Bend[jj].second == j)
			{
				cloth->getParticle(vBend[ii].first,vBend[ii].second).bend.erase(cloth->getParticle(vBend[ii].first,vBend[ii].second).bend.begin()+jj); //v2Shear.erase(v2Shear.begin()+jj);
			}
		}
		//cloth->getParticle(i,j).bend.erase(cloth->getParticle(i,j).bend.begin()+ii); 
	}
	
	//cloth->getParticle(i,j).struc.empty();
	//cloth->getParticle(i,j).bend.empty();
}

vector<Vertex*> Mesh::cleanTriangles()
{
	vector<Vertex *> verts; verts.clear();
	//return verts;
	bool done=false;
	map< Vertex *, bool > triangleVertMap;
	for (int i = 0; i < numVertices(); i++)
		triangleVertMap[getVertex(i)]=false;  //->cleaned=false;
	
	
	for (triangleshashtype::iterator iter = triangles.begin(); iter != triangles.end(); iter++) 
	{
		if(done) break;
		Triangle *t = iter->second;
		if(t)
		{
			Vertex *va = (*t)[0];
			Vertex *vb = (*t)[1];
			Vertex *vc = (*t)[2];
			
			triangleVertMap[va]=true;
			triangleVertMap[vb]=true;
			triangleVertMap[vc]=true;
			/*verts.push_back(va);
			verts.push_back(vb);
			verts.push_back(vc);*/
			
			Edge *ab = getMeshEdge(va,vb);
			Edge *ba = getMeshEdge(vb,va);
			
			Edge *bc = getMeshEdge(vb,vc);
			Edge *cb = getMeshEdge(vc,vb);
			
			Edge *ca = getMeshEdge(vc,va);
			Edge *ac = getMeshEdge(va,vc);
			
			if(va->cleaned==false)
			{
				EraseCutConnections(va); va->cleaned=true;
			}
			if(vb->cleaned==false)
			{
				EraseCutConnections(vb); vb->cleaned=true;
			}
			if(vc->cleaned==false)
			{
				EraseCutConnections(vc); vc->cleaned=true;
			}
			
			if((ab==NULL && ba==NULL) && (bc==NULL && cb==NULL)) 
			{
				//EDGE AC STILL CONNECTED
				//cout<<"NOTHING THERE1"<<endl;
				removeTriangle(t);
				HandleStruc(vb);
				HandleShear(vb);
				
				
				
				/*HandleStruc(va);
				HandleStruc(vb);
				HandleStruc(vc);
				
				HandleShear(va);
				HandleShear(vb);
				HandleShear(vc);*/
				
				
				if(vb->specialEdgePartner)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner));
					edges.erase(std::make_pair(vb->specialEdgePartner,vb));
					//HandleShear(vb,vb->specialEdgePartner);
					ShearIt(vb,vb->specialEdgePartner);
					//ShearIt(vb->specialEdgePartner,vb);
				}
				
				if(vb->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner2));
					edges.erase(std::make_pair(vb->specialEdgePartner2,vb));
						//HandleShear(vb,vb->specialEdgePartner2);
					ShearIt(vb,vb->specialEdgePartner2);
					//ShearIt(vb->specialEdgePartner2,vb);
				}
				
				if(va->specialEdgePartner)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner));
					edges.erase(std::make_pair(va->specialEdgePartner,va));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(va,va->specialEdgePartner);
					//ShearIt(va->specialEdgePartner,va);
				}
				if(va->specialEdgePartner2)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner2));
					edges.erase(std::make_pair(va->specialEdgePartner2,va));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(va,va->specialEdgePartner2);
					//ShearIt(va->specialEdgePartner2,va);
				}
				if(vc->specialEdgePartner)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner));
					edges.erase(std::make_pair(vc->specialEdgePartner,vc));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(vc,vc->specialEdgePartner);
					//ShearIt(vc->specialEdgePartner,vc);
				}
				if(vc->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner2));
					edges.erase(std::make_pair(vc->specialEdgePartner2,vc));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(vc,vc->specialEdgePartner2);
					//ShearIt(vc->specialEdgePartner2,vc);
				}
				
				
				
				//vb->relationshipParticle->struc.empty();
				//vb->relationshipParticle->shear.empty();
				//vb->relationshipParticle->bend.empty();
				
				vb->relationshipParticle->completeCUT = true;
				//va->relationshipParticle->completeCUT = true;
				//vc->relationshipParticle->completeCUT = true;
				
				//va->relationshipParticle->struc.empty();
				//va->relationshipParticle->shear.empty();
				//va->relationshipParticle->bend.empty();
				
				//vc->relationshipParticle->struc.empty();
				//vc->relationshipParticle->shear.empty();
				//vc->relationshipParticle->bend.empty();
				
				EraseCutConnections(va);
				EraseCutConnections(vb);
				EraseCutConnections(vc);
				
				//cout<<"removed triangle!"<<endl;
				done=true;
				break;
			}
			else if((ab==NULL && ba==NULL) && (ca==NULL && ac==NULL)) 
			{
				//EDGE BC STILL CONNECTED
				//cout<<"NOTHING THERE2"<<endl;
				removeTriangle(t);
				HandleStruc(va);
				HandleShear(va);
				/*HandleStruc(va);
				HandleStruc(vb);
				HandleStruc(vc);
				
				HandleShear(va);
				HandleShear(vb);
				HandleShear(vc);*/
				
				if(va->specialEdgePartner)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner));
					edges.erase(std::make_pair(va->specialEdgePartner,va));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(va,va->specialEdgePartner);
					//ShearIt(va->specialEdgePartner,va);
				}
				if(va->specialEdgePartner2)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner2));
					edges.erase(std::make_pair(va->specialEdgePartner2,va));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(va,va->specialEdgePartner2);
					//ShearIt(va->specialEdgePartner2,va);
				}
				
				if(vb->specialEdgePartner)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner));
					edges.erase(std::make_pair(vb->specialEdgePartner,vb));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(vb,vb->specialEdgePartner);
					//ShearIt(vb->specialEdgePartner,vb);
				}
				if(vb->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner2));
					edges.erase(std::make_pair(vb->specialEdgePartner2,vb));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(vb,vb->specialEdgePartner2);
					//ShearIt(vb->specialEdgePartner2,vb);
				}
				if(vc->specialEdgePartner)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner));
					edges.erase(std::make_pair(vc->specialEdgePartner,vc));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(vc,vc->specialEdgePartner);
					//ShearIt(vc->specialEdgePartner,vc);
				}
				if(vc->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner2));
					edges.erase(std::make_pair(vc->specialEdgePartner2,vc));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(vc,vc->specialEdgePartner2);
					//ShearIt(vc->specialEdgePartner2,vc);
				}
				
					
				//va->relationshipParticle->struc.empty();
				//va->relationshipParticle->shear.empty();
				//va->relationshipParticle->bend.empty();
				
				va->relationshipParticle->completeCUT = true;
				//vb->relationshipParticle->completeCUT = true;
				//vc->relationshipParticle->completeCUT = true;
				
				//vb->relationshipParticle->struc.empty();
				//vb->relationshipParticle->shear.empty();
				//vb->relationshipParticle->bend.empty();
				
				//vc->relationshipParticle->struc.empty();
				//vc->relationshipParticle->shear.empty();
				//vc->relationshipParticle->bend.empty();
				
				EraseCutConnections(va);
				EraseCutConnections(vb);
				EraseCutConnections(vc);
				
				//cout<<"removed triangle!"<<endl;
				done=true;
				break;
			}
			else if((bc==NULL && cb==NULL) && (ca==NULL && ac==NULL)) 
			{
				//EDGE AB STILL CONNECTED
				//cout<<"NOTHING THERE3"<<endl;
				removeTriangle(t);
				HandleStruc(vc);
				HandleShear(vc);
				/*HandleStruc(va);
				HandleStruc(vb);
				HandleStruc(vc);
				
				HandleShear(va);
				HandleShear(vb);
				HandleShear(vc);*/
				
				if(vc->specialEdgePartner)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner));
					edges.erase(std::make_pair(vc->specialEdgePartner,vc));
						//HandleShear(vc,vc->specialEdgePartner);
					ShearIt(vc,vc->specialEdgePartner);
					//ShearIt(vc->specialEdgePartner,vc);
				}
				
				if(vc->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner2));
					edges.erase(std::make_pair(vc->specialEdgePartner2,vc));
						//HandleShear(vc,vc->specialEdgePartner2);
					ShearIt(vc,vc->specialEdgePartner2);
					//ShearIt(vc->specialEdgePartner2,vc);
				}
				
				if(va->specialEdgePartner)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner));
					edges.erase(std::make_pair(va->specialEdgePartner,va));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(va,va->specialEdgePartner);
					//ShearIt(va->specialEdgePartner,va);
				}
				if(va->specialEdgePartner2)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner2));
					edges.erase(std::make_pair(va->specialEdgePartner2,va));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(va,va->specialEdgePartner2);
					//ShearIt(va->specialEdgePartner2,va);
				}
				
				if(vb->specialEdgePartner)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner));
					edges.erase(std::make_pair(vb->specialEdgePartner,vb));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(vb,vb->specialEdgePartner);
					//ShearIt(vb->specialEdgePartner,vb);
				}
				if(vb->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner2));
					edges.erase(std::make_pair(vb->specialEdgePartner2,vb));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(vb,vb->specialEdgePartner2);
					//ShearIt(vb->specialEdgePartner2,vb);
				}
				
				//vc->relationshipParticle->struc.empty();
				//vc->relationshipParticle->shear.empty();
				//vc->relationshipParticle->bend.empty();
				
				vc->relationshipParticle->completeCUT = true;
				//va->relationshipParticle->completeCUT = true;
				//vb->relationshipParticle->completeCUT = true;
				
				//va->relationshipParticle->struc.empty();
				//va->relationshipParticle->shear.empty();
				//va->relationshipParticle->bend.empty();
				
				//vb->relationshipParticle->struc.empty();
				//vb->relationshipParticle->shear.empty();
				//vb->relationshipParticle->bend.empty();
				
				//cout<<"removed triangle!"<<endl;
				/*verts.push_back(va);
				verts.push_back(vb);
				verts.push_back(vc);*/
				
				EraseCutConnections(va);
				EraseCutConnections(vb);
				EraseCutConnections(vc);
				
				done=true;
				//for(unsigned int i=0; i<
				break;
			}
			else if(va->relationshipParticle->completeCUT || vb->relationshipParticle->completeCUT || vc->relationshipParticle->completeCUT)
			{
				//cout<<"removing the triangle"<<endl;
				removeTriangle(t);
				/*EraseCutConnections(va);
				EraseCutConnections(vb);
				EraseCutConnections(vc);*/
				
				if(va->relationshipParticle->completeCUT)
				{
					HandleStruc(va);
					HandleShear(va);
				}
				else if(vb->relationshipParticle->completeCUT)
				{
					HandleStruc(vb);
					HandleShear(vb);
				}
				else
				{
					HandleStruc(vc);
					HandleShear(vc);
				}
				
				//ShearIt(va,vb);
				//ShearIt(va,vc);
				//ShearIt(vb,va);
				//ShearIt(vb,vc);
				//ShearIt(vc,va);
				//ShearIt(vc,vb);
				
				//cout<<"done removing the triangle"<<endl;
				if(vc->specialEdgePartner)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner));
					edges.erase(std::make_pair(vc->specialEdgePartner,vc));
						//HandleShear(vc,vc->specialEdgePartner);
					ShearIt(vc,vc->specialEdgePartner);
					//ShearIt(vc->specialEdgePartner,vc);
				}
				
				if(vc->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vc,vc->specialEdgePartner2));
					edges.erase(std::make_pair(vc->specialEdgePartner2,vc));
						//HandleShear(vc,vc->specialEdgePartner2);
					ShearIt(vc,vc->specialEdgePartner2);
					//ShearIt(vc->specialEdgePartner2,vc);
				}
				
				if(va->specialEdgePartner)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner));
					edges.erase(std::make_pair(va->specialEdgePartner,va));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(va,va->specialEdgePartner);
					//ShearIt(va->specialEdgePartner,va);
				}
				if(va->specialEdgePartner2)
				{
					edges.erase(std::make_pair(va,va->specialEdgePartner2));
					edges.erase(std::make_pair(va->specialEdgePartner2,va));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(va,va->specialEdgePartner2);
					//ShearIt(va->specialEdgePartner2,va);
				}
				
				if(vb->specialEdgePartner)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner));
					edges.erase(std::make_pair(vb->specialEdgePartner,vb));
						//HandleShear(va,va->specialEdgePartner);
					ShearIt(vb,vb->specialEdgePartner);
					//ShearIt(vb->specialEdgePartner,vb);
				}
				if(vb->specialEdgePartner2)
				{
					edges.erase(std::make_pair(vb,vb->specialEdgePartner2));
					edges.erase(std::make_pair(vb->specialEdgePartner2,vb));
						//HandleShear(va,va->specialEdgePartner2);
					ShearIt(vb,vb->specialEdgePartner2);
					//ShearIt(vb->specialEdgePartner2,vb);
				}
				break;
			}
			
		}
	}
	
	map<Vertex *,bool>::iterator it;
	for ( it=triangleVertMap.begin() ; it != triangleVertMap.begin(); it++ )
	{
		if( !(*it).second )
		{
			HandleStruc( (*it).first );
			HandleShear( (*it).first );
			/*(*it).first->relationshipParticle->struc.empty();
			(*it).first->relationshipParticle->shear.empty();
			(*it).first->relationshipParticle->bend.empty();*/
			
			if((*it).first->specialEdgePartner)
			{
				//edges.erase(std::make_pair(vb,vb->specialEdgePartner));
				//edges.erase(std::make_pair(vb->specialEdgePartner,vb));
					//HandleShear(va,va->specialEdgePartner);
				ShearIt((*it).first,(*it).first->specialEdgePartner);
				//ShearIt(vb->specialEdgePartner,vb);
			}
			if((*it).first->specialEdgePartner2)
			{
				//edges.erase(std::make_pair(vb,vb->specialEdgePartner2));
				//edges.erase(std::make_pair(vb->specialEdgePartner2,vb));
					//HandleShear(va,va->specialEdgePartner2);
				ShearIt((*it).first,(*it).first->specialEdgePartner2);
				//ShearIt(vb->specialEdgePartner2,vb);
			}
		}
	}
		//cout << (*it).first << " => " << (*it).second << endl;
	
	/*for(unsigned int k=0; k<numVertices(); k++)
	{
		bool there=false;
		if(!getVertex(k)->clearedClean)
		{
			for(unsigned int l=0; l<verts.size(); l++)
			{
				if(verts[l] == getVertex(k))
				{
					there=true;
					break;
				}
			}
			if(!there)
			{
				HandleStruc(getVertex(k));
				HandleShear(getVertex(k));
				//getVertex(k)->relationshipParticle->struc.empty();
				//getVertex(k)->relationshipParticle->shear.empty();
				//getVertex(k)->relationshipParticle->bend.empty();
				getVertex(k)->clearedClean=true;
				break;
			}
		}
	}
	verts.clear();*/
	
	return verts;
}

// =======================================================================
// PAINT
// =======================================================================

Vec3f ComputeNormal(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) {
  Vec3f v12 = p2;
  v12 -= p1;
  Vec3f v23 = p3;
  v23 -= p2;
  Vec3f normal;
  Vec3f::Cross3(normal,v12,v23);
  normal.Normalize();
  return normal;
}

void InsertNormal(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) {
  Vec3f normal = ComputeNormal(p1,p2,p3);
  glNormal3f(normal.x(), normal.y(), normal.z());
}

void Mesh::Paint(ArgParser *args, int curmouseX, int curmouseY, GLuint the_texture) {


  // scale it so it fits in the window
  Vec3f center; //bbox.getCenter(center);
  float s = 1/bbox.maxDim();
  glScalef(s,s,s);
  glTranslatef(-center.x(),-center.y(),-center.z());

  // this offset prevents "z-fighting" bewteen the edges and faces
  // the edges will always win.
  glEnable(GL_POLYGON_OFFSET_FILL);
  glPolygonOffset(1.1,4.0);

  //glColor3f(0,1,0);

  
  glEnable(GL_TEXTURE_2D);
  glBindTexture (GL_TEXTURE_2D, the_texture);
  glBegin (GL_TRIANGLES);        // MAKE THIS SHIT HAPPEN 
  //std::cout << "paintin'" << std::endl;
  for (triangleshashtype::iterator iter = triangles.begin(); iter != triangles.end(); iter++) 
  {
      Triangle *t = iter->second;
      Vec3f a = (*t)[0]->getPos();
      Vec3f ta = (*t)[0]->getOriginalPos();
      //std::cout << "orig pos ta.x is " << ta.x() << std::endl;
      //if (iter == triangles.begin()) std::cout << a << std::endl;
      Vec3f b = (*t)[1]->getPos();
      Vec3f tb = (*t)[1]->getOriginalPos();
      Vec3f c = (*t)[2]->getPos();
      Vec3f tc = (*t)[2]->getOriginalPos();
  
      InsertNormal(a,b,c); 
      glTexCoord3f(ta.x()-.5,ta.y()-.5,ta.z()-.1);glVertex3f(a.x()-.5,a.y()-.5,a.z()-.1);
      glTexCoord3f(tb.x()-.5,tb.y()-.5,tb.z()-.1);glVertex3f(b.x()-.5,b.y()-.5,b.z()-.1);
      glTexCoord3f(tc.x()-.5,tc.y()-.5,tc.z()-.1);glVertex3f(c.x()-.5,c.y()-.5,c.z()-.1);
      
  }


  glEnd();
  
  glDisable(GL_COLOR_MATERIAL);
  //glEnable(GL_TEXTURE_2D);
  //glBindTexture ( GL_TEXTURE_2D, texture_id[0] );

         
 /* glBegin(GL_POINTS);

  for(unsigned int i=0; i<vertices.size(); i++)
  {
	Vec3f a = vertices[i]->getPos();
	glVertex3f(a.x()-.5,a.y()-.5,a.z()-.1);
  }
  glEnd();*/

  glEnable(GL_COLOR_MATERIAL);
  glDisable(GL_TEXTURE_2D);
   glDisable(GL_POLYGON_OFFSET_FILL); 
   //Alles wird wie vorher
   //glDisable(GL_BLEND);
   //glEnable(GL_DEPTH_TEST);
   ///////////////////////////////////////////////////////////
   

  // =================================
  if (args->wireframe) {
    glDisable(GL_LIGHTING);

    // draw all the interior, non-crease edges
    glLineWidth(1);
    glColor3f(0,0,0);
    glBegin (GL_LINES);
    for (edgeshashtype::iterator iter = edges.begin();
	 iter != edges.end(); iter++) {
      Edge *e = iter->second;
      if (e->getOpposite() == NULL || e->getCrease() > 0) continue;
      Vec3f a = e->getStartVertex()->getPos();
      Vec3f b = e->getEndVertex()->getPos();
      glVertex3f(a.x(),a.y(),a.z());
      glVertex3f(b.x(),b.y(),b.z());
    }
    glEnd();

    // draw all the interior, crease edges
    glLineWidth(3);
    glColor3f(1,1,0);
    glBegin (GL_LINES);
    for (edgeshashtype::iterator iter = edges.begin();
	 iter != edges.end(); iter++) {
      Edge *e = iter->second;
      if (e->getOpposite() == NULL || e->getCrease() == 0) continue;
      Vec3f a = e->getStartVertex()->getPos();
      Vec3f b = e->getEndVertex()->getPos();
      glVertex3f(a.x(),a.y(),a.z());
      glVertex3f(b.x(),b.y(),b.z());
    }
    glEnd();

    // draw all the boundary edges
    glLineWidth(3);
    glColor3f(1,0,0);
    glBegin (GL_LINES);
    for (edgeshashtype::iterator iter = edges.begin();
	 iter != edges.end(); iter++) {
      Edge *e = iter->second;
      if (e->getOpposite() != NULL) continue;
      assert (e->getCrease() == 0);
      Vec3f a = e->getStartVertex()->getPos();
      Vec3f b = e->getEndVertex()->getPos();
      glVertex3f(a.x()-.5,a.y()-.5,a.z()-.1);
      glVertex3f(b.x()-.5,b.y()-.5,b.z()-.1);
    }
    glEnd();

    glEnable(GL_LIGHTING);
  }

  HandleGLError(); 
}

